package com.bidevalution.business.impl;

import com.bidevalution.business.service.BeExpertVoteService;
import com.bidevalution.dao.entity.*;
import com.bidevalution.dao.mapper.BeExpertVoteDetailMapper;
import com.bidevalution.dao.mapper.BeExpertVoteMapper;
import com.bidevalution.dao.mapper.BeSectionExpertInfoMapper;
import com.qtp.common.DefaultSpringContextUtil;
import com.qtp.common.data.RedisAccess;
import com.qtp.core.model.Response;
import com.qtp.core.redis.RedisUtil;
import com.qtp.core.util.GsonUtil;
import com.qtp.core.util.OConvertUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by 查慧英 on 2020-04-08.
 */
@Service(value = "beExpertVoteService")
public class BeExpertVoteServiceImpl implements BeExpertVoteService {
    private static final String SECTION_ID = "sectionId";
    private static final String EXPERT_RESULE = "expertResule";
    private static final String VOTE_SUB_ID = "voteSubId";
    private static final String NEXT_JOB = "nextJob";
    private static final String REMARk = "remark";
    private static final String FORMAT_LIST = "voteList_%s_%s";
    private static final String FORMAT_REDIS = "voteList_%s";
    private static final String EXPERT_ID = "expertId";
    private static final String VOTE_STATUS = "voteStatus";
    private static final String LOGIN_NAME = "loginName";
    private static final String VOTE_ALGORITHM = "voteAlgorithm";
    private static final String SEQ_ID = "seqId";
    private static final String VOTE_RESULE = "voteResule";
    private static final String SECTION_STEP_ID = "sectionStepId";
    private static final String VOTE_PARAMS = "voteParams";
    private static final int REDIS_EXPIRE_TIME = 14400;
    @Autowired(required = false)
    BeExpertVoteMapper beExpertVoteMapper;
    @Autowired(required = false)
    BeExpertVoteDetailMapper beExpertVoteDetailMapper;
    @Autowired(required = false)
    private BeSectionExpertInfoMapper beSectionExpertInfoMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response addForVote(List<BeExpertVoteExt> expertVoteList) {
        if (expertVoteList != null && !expertVoteList.isEmpty()) {
            String sectionId = expertVoteList.get(0).getSectionId();
            String voting = RedisAccess.getValue(String.class, sectionId);
            if (OConvertUtils.isNotEmpty(voting)) {
                return Response.fail("正在表决中，不能发起另外的表决!");
            }
            BeExpertVote expertVote;
            RedisAccess.add(sectionId, sectionId);
            RedisUtil.expire(sectionId, REDIS_EXPIRE_TIME);
            String voteId;
            for (BeExpertVoteExt expertVoteExt: expertVoteList) {
                expertVote = new BeExpertVote();
                voteId = UUID.randomUUID().toString();
                expertVote.setSeqId(voteId);
                expertVote.setOriginator(expertVoteExt.getOriginator());
                expertVote.setVoteOptions(expertVoteExt.getVoteOptions());
                expertVote.setVoteType(expertVoteExt.getVoteType());
                expertVote.setVoteAlgorithm(expertVoteExt.getVoteAlgorithm());
                expertVote.setContent(expertVoteExt.getContent());
                expertVote.setTitle(expertVoteExt.getTitle());
                expertVote.setSectionId(expertVoteExt.getSectionId());
                expertVote.setNextJob(expertVoteExt.getNextJob());
                expertVote.setSectionStepId(expertVoteExt.getSectionStepId());
                expertVote.setVoteParams(expertVoteExt.getVoteParams());
                expertVote.setVoteStatus(10);
                expertVote.setCreateTime(new Date());
                beExpertVoteMapper.insertSelective(expertVote);
                List<BeExpertVoteDetailExt> voteDetailList = expertVoteExt.getVoteDetailList();
                if (voteDetailList != null && !voteDetailList.isEmpty()) {
                    addExpertVoteDetail(voteId, voteDetailList);
                }
            }
            return Response.ok();
        } else {
            return Response.fail("表决列表为空！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response submitVote(String voteJson, String loginName) {
        List<Map<String, Object>> list = GsonUtil.jsonToListMapWithGson(voteJson);
        if (list != null && !list.isEmpty()) {
            Map<String, Object> map = list.get(0);
            String sectionId = OConvertUtils.getString(map.get(SECTION_ID));
            BeExpertVoteDetail voteDetail;
            for (Map<String, Object> item : list) {
                voteDetail = new BeExpertVoteDetail();
                voteDetail.setSeqId(OConvertUtils.getString(item.get(VOTE_SUB_ID)));
                voteDetail.setVoteResule(OConvertUtils.getString(item.get(EXPERT_RESULE)));
                voteDetail.setRemark(OConvertUtils.getString(item.get(REMARk)));
                voteDetail.setUpdateTime(new Date());
                beExpertVoteDetailMapper.updateByPrimaryKeySelective(voteDetail);
            }
            //最后一个提交的专家统计最终的表决结果并更新表决完成状态及最终表决结果、调回调类
            judgeLastSubmit(sectionId, map);
            //删除redis中的列表
            String redisKey = String.format(FORMAT_REDIS, sectionId);
            RedisUtil.delete(redisKey);
            return Response.ok();
        } else {
            return Response.fail("提交表决为空！");
        }
    }

    @Override
    public Response<List<Map>> getBeingVoteList(Map<String, Object> params) {
        String expertId = getExpertId(params);
        params.put(EXPERT_ID, expertId);
        String sectionId = OConvertUtils.getString(params.get(SECTION_ID));
        String listKey = String.format(FORMAT_LIST, sectionId, expertId);
        String redisKey = String.format(FORMAT_REDIS, sectionId);
        Map<String, Object> redisMap = RedisAccess.getValue(Map.class, redisKey);
        List<Map> list = null;
        if (redisMap != null && !redisMap.isEmpty()) {
            list = (List<Map>) redisMap.get(listKey);
        }
        if (list == null || list.isEmpty()) {
            list = updateRedisList(params);
        }
        return Response.ok(list);
    }

    @Override
    public Response<List<Map>> getVotingRecordList(Map<String, Object> params) {
        String expertId = getExpertId(params);
        params.put(EXPERT_ID, expertId);
        return Response.ok(beExpertVoteMapper.getList(params));
    }

    @Override
    public Response toUpdateTheVote(List<BeExpertVoteCallBack> voteCallBackList) {
        return null;
    }

    /**
     *  新增表决子表数据
     * @param voteId 投票主表Id
     * @param voteDetailList 表决子表数据列表
     */
    private void addExpertVoteDetail(String voteId, List<BeExpertVoteDetailExt> voteDetailList) {
        BeExpertVoteDetail voteDetail;
        for (BeExpertVoteDetailExt item : voteDetailList) {
            voteDetail = new BeExpertVoteDetail();
            voteDetail.setSeqId(UUID.randomUUID().toString());
            voteDetail.setVoteId(voteId);
            voteDetail.setExpertId(item.getExpertId());
            voteDetail.setOwnJudge(item.getOwnJudge());
            voteDetail.setCreateTime(new Date());
            beExpertVoteDetailMapper.insertSelective(voteDetail);
        }
    }

    /**
     * 判断是否是最后一个专家提交
     * @param sectionId 标段Id
     * @param map 表决列表第一条数据对象
     */
    private void judgeLastSubmit(String sectionId, Map<String, Object> map) {
        long count = beExpertVoteMapper.judgeLastSubmit(sectionId);
        if (count == 0) {
            Boolean delRedisFlag = true;
            String nextJob = OConvertUtils.getString(map.get(NEXT_JOB));
            int voteAlgorithm = OConvertUtils.getInt(map.get(VOTE_ALGORITHM));
            //更新表决完成状态及最终表决结果
            List<BeExpertVoteCallBack> voteCallBackList = null;
            if (voteAlgorithm == 0) {
                //获取少数服从多数表决情况列表
                List<Map<String, Object>> list = beExpertVoteMapper.getMajorityRulesVoteResultList(sectionId);
                voteCallBackList = votePassedResultList(sectionId, nextJob, map, list);
            } else {
                //获取一票否决算法，全票通过的列表
                List<Map<String, Object>> list = beExpertVoteMapper.getOneVoteNoVoteResultList(sectionId);
                voteCallBackList = votePassedResultList(sectionId, nextJob, map, list);
                //一票否决未通过的处理,再次发起表决
                delRedisFlag = voteNotPassedCallForVote(sectionId);
            }
            //回调类更新评审详情及汇总结果表中的数据
            if (voteCallBackList != null && !voteCallBackList.isEmpty()) {
                BeExpertVoteService voteService = getEO(nextJob);
                if (voteService != null) {
                    voteService.toUpdateTheVote(voteCallBackList);
                }
            }
            if (delRedisFlag) {
                RedisUtil.delete(sectionId);
            }
        }
    }

    /**
     *  一票否决的重新发起表决处理
     * @param sectionId 标段id
     */
    private Boolean voteNotPassedCallForVote(String sectionId) {
        List<BeExpertVote> voteList = beExpertVoteMapper.selectBySectionId(beExpertVoteMapper);
        if (voteList != null && !voteList.isEmpty()) {
            BeExpertVote item = new BeExpertVote();
            item.setUpdateTime(new Date());
            item.setSectionId(sectionId);
            item.setVoteStatus(20);
            beExpertVoteMapper.updateStatusBySectionId(item);
            String seqId;
            for (BeExpertVote vote : voteList) {
                seqId = UUID.randomUUID().toString();
                vote.setSeqId(seqId);
                vote.setCreateTime(new Date());
                vote.setUpdateTime(new Date());
                beExpertVoteMapper.insertSelective(vote);
                List<BeExpertVoteDetail> voteDetailList = beExpertVoteDetailMapper.getVoteListByVoteId(vote.getSeqId());
                if (voteDetailList != null && !voteDetailList.isEmpty()) {
                    for (BeExpertVoteDetail voteDetail : voteDetailList) {
                        voteDetail.setSeqId(UUID.randomUUID().toString());
                        voteDetail.setRemark("");
                        voteDetail.setVoteResule("");
                        voteDetail.setCreateTime(new Date());
                        voteDetail.setUpdateTime(new Date());
                        voteDetail.setVoteId(seqId);
                        beExpertVoteDetailMapper.insertSelective(voteDetail);
                    }
                }
            }
            return false;
        }
        return true;
    }

    /**
     * 组装表决完后回调需要的数据
     * @param sectionId  标段Id
     * @param nextJob 回调类
     * @param map 表决列表第一条数据对象
     * @param list 表决情况列表
     * @return 回调需要的数据列表
     */
    private List<BeExpertVoteCallBack> votePassedResultList(String sectionId, String nextJob, Map<String, Object> map, List<Map<String, Object>> list) {
        BeExpertVote expertVote;
        List<BeExpertVoteCallBack> voteCallBackList = new ArrayList<>();
        BeExpertVoteCallBack voteCallBack;
        String voteResule;
        String seqId;
        for (Map<String, Object> item : list) {
            voteResule = OConvertUtils.getString(item.get(VOTE_RESULE));
            seqId = OConvertUtils.getString(item.get(SEQ_ID));
            expertVote = new BeExpertVote();
            expertVote.setSeqId(seqId);
            expertVote.setVoteStatus(20);
            expertVote.setVoteResule(voteResule);
            expertVote.setUpdateTime(new Date());
            beExpertVoteMapper.updateByPrimaryKey(expertVote);
            if (OConvertUtils.isNotEmpty(nextJob)) {
                //组装回调的参数
                voteCallBack = new BeExpertVoteCallBack();
                String sectionStepId = OConvertUtils.getString(map.get(SECTION_STEP_ID));
                String voteParams = OConvertUtils.getString(map.get(VOTE_PARAMS));
                voteCallBack.setSectionId(sectionId);
                voteCallBack.setSectionStepId(sectionStepId);
                voteCallBack.setVoteParams(voteParams);
                voteCallBack.setSeqId(seqId);
                voteCallBack.setVoteResule(voteResule);
                //每个专家表决情况列表
                List<BeExpertVoteDetailExt> voteDetailList = beExpertVoteDetailMapper.getExpertVoteListByVoteId(seqId);
                voteCallBack.setVoteDetailList(voteDetailList);
                voteCallBackList.add(voteCallBack);
            }
        }
        return voteCallBackList;
    }

    /**
     * 根据code获取接口实现
     * @param cls 回调类
     * @return 结果
     */
    private BeExpertVoteService getEO(String cls) {
        String tmpCls = StringUtils.isBlank(cls) ? "" : cls;
        //用code获取cls
        if(StringUtils.isNotBlank(tmpCls)) {
            return (BeExpertVoteService)DefaultSpringContextUtil.getBean(tmpCls);
        }
        return null;
    }

    /**
     * 更新redis中的表决列表
     * @param params 参数
     * @return 表决列表
     */
    private List<Map> updateRedisList(Map<String, Object> params) {
        String sectionId = OConvertUtils.getString(params.get(SECTION_ID));
        String expertId = OConvertUtils.getString(params.get(EXPERT_ID));
        List<Map> list = beExpertVoteMapper.getList(params);
        String listKey = String.format(FORMAT_LIST, sectionId, expertId);
        String redisKey = String.format(FORMAT_REDIS, sectionId);
        Map<String, Object> redisMap = RedisAccess.getValue(Map.class, redisKey);
        if (redisMap == null || redisMap.isEmpty()) {
            redisMap = new HashMap<>(16);
        }
        redisMap.put(listKey, list);
        RedisAccess.add(redisMap, redisKey);
        RedisUtil.expire(redisKey, REDIS_EXPIRE_TIME);
        return list;
    }
    /**
     * 获取专家信息
     * @param parameters 参数
     * @return 专家信息
     */
    private String getExpertId(Map<String,Object> parameters) {
        String expertId = null;
        String loginName = OConvertUtils.getString(parameters.get(LOGIN_NAME));
        String sectionId = OConvertUtils.getString(parameters.get(SECTION_ID));
        BeSectionExpertInfo expertInfo = beSectionExpertInfoMapper.selectByLoginName(sectionId, loginName);
        if (expertInfo != null) {
            expertId = expertInfo.getSeqId();
        }
        return expertId;
    }
}
